﻿/*
 * Vytvořeno aplikací SharpDevelop.
 * Uživatel: lebeda
 * Datum: 28.5.2012
 * Čas: 20:24
 * 
 * Tento template můžete změnit pomocí Nástroje | Možnosti | Psaní kódu | Upravit standardní hlavičky souborů.
 */
// TODO - upravit hlavičky souborů
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

using CommandLine;
using Lucene.Net.Analysis;
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Documents;
using Lucene.Net.Index;
using Lucene.Net.QueryParsers;
using Lucene.Net.Search;
using Lucene.Net.Store;

using SevenZip;

namespace updatedb
{
    class Program
    {
        
        public static void Main(string[] args)
        {
            
            var options = new CmdOptions();
            
            if (args.Length == 0) {
                Console.WriteLine(options.GetUsage());
                return;
            }
            
            if (!CommandLineParser.Default.ParseArguments(args, options)) {
                System.Environment.Exit(0);
            }

            LocateCommons.waitForReleaseIndexLock();            
            Lucene.Net.Store.Directory directory = LocateCommons.GetIndexDirectory();
            Analyzer analyzer = new KeywordAnalyzer();
            //            Analyzer analyzer = new StandardAnalyzer();
            //            Analyzer analyzer = new SimpleAnalyzer();
            IndexWriter indexWriter = new IndexWriter(directory, analyzer, LocateCommons.forceCreateIndex(), IndexWriter.MaxFieldLength.UNLIMITED);
            
            try {
                
                // start of standalone delete
                if (!String.IsNullOrEmpty(options.pathToDelete)) {
                    string pathToDelete = LocateCommons.TrimLastPathSeparator(options.pathToDelete);
                    pathToDelete = LocateCommons.LowerDriveChar(pathToDelete);
                    LocateCommons.LogToConsole("deleting path from index: "+pathToDelete);
                    
                    IndexSearcher searcher = new IndexSearcher(directory, true);
                    Query query = LocateCommons.getQueryPath(pathToDelete);
                    indexWriter.DeleteDocuments(query);
                    
                    LocateCommons.LogToConsole("deleted");
                }
                // end of standalone delete
                
                
                // start of indexing
                //                if (!String.IsNullOrEmpty(options.pathToIndex)) {
                foreach (var toIndexVar in options.pathToIndex) {
                    string toIndex = LocateCommons.LowerDriveChar(toIndexVar);
                    string pathToIndex;
                    List<string> files = new List<string>();
                    
                    if (System.IO.Directory.Exists(toIndex)) {
                        LocateCommons.LogToConsole("scanning path: "+toIndex);
                        pathToIndex = LocateCommons.TrimLastPathSeparator(toIndex);
                        files.AddRange(getFsEntries(toIndex, options.excludeList));
                        if (options.Archive) {
                            files.AddRange(getArchiveList(files, options.storeIndexArchives));
                        }
                    } else if (File.Exists(toIndex)) {
                        LocateCommons.LogToConsole("indexed source file: "+toIndex);
                        files.AddRange(System.IO.File.ReadAllLines(toIndex));
                        pathToIndex = Path.GetDirectoryName(files[0]);
                        LocateCommons.LogToConsole("indexed path: "+toIndex);
                    } else {
                        LocateCommons.LogToConsole("Source is not found: "+toIndex);
                        break;
                    }
                    
                    LocateCommons.LogToConsole("indexed path: "+pathToIndex+"; found "+files.Count+" items");
                    
                    // delete
                    IndexSearcher searcher = new IndexSearcher(directory, true);
                    Query query = LocateCommons.getQueryPath(pathToIndex);
                    indexWriter.DeleteDocuments(query);
                    // end delete
                    
                    LocateCommons.LogToConsole("deleted old items");
                    
                    foreach (string file in files)
                    {
                        if (!containsExclude(file, options.excludeList)) {
                            try {
                                int lastSep = file.LastIndexOf("\\") + 1;
                                string fileNoDia = file.Substring(lastSep);
                                // string fileNoDia = Path.GetFileName(file); // Too often detects invalid characters
                                fileNoDia = LocateCommons.LatinToAscii(fileNoDia);
                                fileNoDia = fileNoDia.ToLower();
                                
                                Document doc = new Document();
                                doc.Add(new Field(LocateCommons.COL_TYPE, LocateCommons.TYPE_FILE, Field.Store.YES, Field.Index.NOT_ANALYZED));
                                doc.Add(new Field(LocateCommons.COL_CONTENT, fileNoDia, Field.Store.YES, Field.Index.ANALYZED));
                                doc.Add(new Field(LocateCommons.COL_KEY, file, Field.Store.YES, Field.Index.NOT_ANALYZED));
                                indexWriter.AddDocument(doc);
                            } catch (Exception e) {
                                LocateCommons.LogToConsole("Unable to index: " + file +" ,e: " + e.Message);
                            }
                        }
                    }
                    
                    LocateCommons.LogToConsole("indexed");
                }
                // end of indexing
                
                if (options.Optimize) {
                    LocateCommons.LogToConsole("optimizing started");
                    indexWriter.Optimize();
                    LocateCommons.LogToConsole("optimized");
                } else {
                    LocateCommons.LogToConsole("optimize skiped");
                }
                
            } finally {
                
                //Close the writer
                indexWriter.Dispose();
                
                LocateCommons.LogToConsole("done");
                
            }
        }
        
        private static List<string> getFsEntries(string toIndex, IList<string> excludeList)
        {
            var resultList = new List<string>();
            
            string[] dirList = new string[0];
            
            try {
                resultList.AddRange(System.IO.Directory.GetFiles(toIndex));
                
                dirList = System.IO.Directory.GetDirectories(toIndex);
                resultList.AddRange(dirList);
            }
            catch (Exception e)
            {
                LocateCommons.LogToConsole("Unable to index path: "+ toIndex + " ("+ e.Message +")");
            }
            
            foreach (var subPath in dirList) {
                if (!containsExclude(subPath, excludeList)) {
                    resultList.AddRange(getFsEntries(subPath, excludeList));
                }
            }
            
            return resultList;
        }
        
        private static List<string> getArchiveList(List<string> fileList, bool storeIndex)
        {
            var resultList = new List<string>();
            int archiveCnt = 0;
            foreach(string filename in fileList) {
                if (LocateCommons.gotoArchive(filename)) {
                    try {
                        
                        // load index of archive
                        string filenameLst = filename + ".lst";
                        List<string> archiveList = new List<string>();
                        if (checkExistsAktualLst(filename, filenameLst)) {
                            archiveList.AddRange(File.ReadLines(filenameLst));
                        } else {
                            SevenZipExtractor zip = new SevenZipExtractor(filename);
                            archiveList.AddRange(zip.ArchiveFileNames);
                            
                            if (storeIndex) {
                                File.WriteAllLines(filenameLst, archiveList);
                            }
                        }
                        
                        // indexing content of archive
                        foreach (var archiveFile in archiveList) {
                            resultList.Add(filename + "\\" + archiveFile);
                        }
                        archiveCnt++;
                    }
                    catch (Exception e)
                    {
                        LocateCommons.LogToConsole("Unable to index archive: "+filename + " ("+ e.Message +")");
                    }
                }
            }
            LocateCommons.LogToConsole("Archives: "+archiveCnt);
            
            return resultList;
        }
        
        private static Boolean checkExistsAktualLst(string archiveFileName, string listFileName)
        {
            FileInfo archFile = new FileInfo(archiveFileName);
            FileInfo listFile = new FileInfo(listFileName);
            
            return listFile.Exists && (listFile.LastWriteTime >= archFile.LastWriteTime);
        }
        
        private static Boolean containsExclude(string file, IList<string> excludeList)
        {
            if (excludeList != null) {
                foreach(string excludeString in excludeList) {
                    if (file.Contains(excludeString)) {
                        return true;
                    }
                }
            }
            return false;
        }


        
    }
}